package com.jimet.objects;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;


public class JimetObjects {
	public int pos;
	public Vector<Object> objectsVec;
	protected Class<?> db;
	protected Class<?> object;
	protected Thread t = Thread.currentThread();
	protected ClassLoader cl = t.getContextClassLoader();
	
	
	public JimetObjects() {
		// TODO Auto-generated constructor stub
	}

	public int size()
	{
		if(this.isNull())
			return 0;
		else
			return this.objectsVec.size();
	}

	public void store() throws Exception
	{
		JimetObjects toBeAdded 	 = this.getClass().newInstance();
		JimetObjects toBeUpdated = this.getClass().newInstance();
		
		Method getId = object.getMethod("getId");
		
		
		while(this.next())
		{
			if( ( Long.valueOf(getId.invoke(this.getNext()).toString()) )==-1 ) 
					toBeAdded.add(this.getNext());
			else
				toBeUpdated.add(this.getNext());
		}
		
		JimetDB jimetDb = (JimetDB) db.newInstance();
		
		if(toBeAdded.size()>0)
			jimetDb.addBatch(toBeAdded);
		if(toBeUpdated.size()>0)
			jimetDb.updateBatch(toBeUpdated);
		
		jimetDb.disconnect();

	}

	public boolean delete() throws Exception
	{
		JimetDB jimetDb = (JimetDB) db.newInstance();
		boolean res = jimetDb.deleteBatch(this);
		jimetDb.disconnect();
		return res;
	}

	public void load( String strSort, String strOrderBy  )  throws Exception 
	{
		HashMap<String,String> fieldMapValueProp = new HashMap<String,String>();
		if(strSort==null) strSort = "ASC";
		if(strOrderBy==null) strOrderBy = "id";
		long startIndex = -1L;
		long endIndex = -1L;
		
		this.pos = -1;
		this.objectsVec = new Vector<Object>();
		
		HashMap<Object,Object> passMap = new HashMap<Object, Object>();
		
		for (Map.Entry<String, String> entry: fieldMapValueProp.entrySet()) 
		{
			String key = entry.getKey();
			String value = entry.getValue();
			
			if(key.indexOf('.')==-1)
			passMap.put(key, value);
			else
			{
				String[] strVals = key.split("\\.");
				passMap.put(this.object.getDeclaredField(strVals[0]).getType(), new String[]{strVals[0],strVals[1],value});
			}
		
		}
		
		JimetDB jimetDb = (JimetDB) db.newInstance();
		ResultSet rs = jimetDb.getResultSetByFieldsWithExpr(passMap,strSort, strOrderBy, startIndex, endIndex);
		TemplateUtil util = new TemplateUtil();

		LinkedHashMap<String, String> dbFieldProp = jimetDb.getDbFieldProp();
		
		Set<String> st = dbFieldProp.keySet();
		Iterator<String> iter = st.iterator();
		Class<?> wrapperClass = object;
		
		while(rs.next())
		{

			iter = st.iterator();
			Object obj = wrapperClass.getConstructor(boolean.class).newInstance(false);

			while(iter.hasNext())
			{
				String key = iter.next();
				Field field = wrapperClass.getDeclaredField(key);
				Method mt 	= null;
				try {
					Field clobField = wrapperClass.getDeclaredField(key+"CLOB");
					mt = wrapperClass.getMethod("set"+util.getFirstCaseUpper(key+"CLOB"),clobField.getType());
				}
				catch ( NoSuchFieldException nsfEx ) {
					mt 	= wrapperClass.getMethod("set"+util.getFirstCaseUpper(key),field.getType());
				}
				mt.invoke(obj, rs.getObject(key));
			}
			
			this.add(obj);
		}
		jimetDb.disconnect();
	}
	
	public void loadAny( HashMap<String,String> fieldMapValueProp,String strSort, String strOrderBy ,Long startIndex, Long endIndex )  throws Exception 
	{
		if(fieldMapValueProp==null) fieldMapValueProp = new HashMap<String,String>();
		if(strSort==null) strSort = "ASC";
		if(strOrderBy==null) strOrderBy = "id";
		if(startIndex==null) startIndex = -1L;
		if(endIndex==null) endIndex = -1L;
		
		this.pos = -1;
		this.objectsVec = new Vector<Object>();
		
		HashMap<Object,Object> passMap = new HashMap<Object, Object>();
		
		for (Map.Entry<String, String> entry: fieldMapValueProp.entrySet()) 
		{
			String key = entry.getKey();
			String value = entry.getValue();
			
			if(key.indexOf('.')==-1)
			passMap.put(key, value);
			else
			{
				String[] strVals = key.split("\\.");
				passMap.put(this.object.getDeclaredField(strVals[0]).getType(), new String[]{strVals[0],strVals[1],value});
			}
		
		}
		
		JimetDB jimetDb = (JimetDB) db.newInstance();
		ResultSet rs = jimetDb.getResultSetByFieldsWithExpr(passMap, "OR", strSort, strOrderBy, startIndex, endIndex);
		TemplateUtil util = new TemplateUtil();

		LinkedHashMap<String, String> dbFieldProp = jimetDb.getDbFieldProp();
		
		Set<String> st = dbFieldProp.keySet();
		Iterator<String> iter = st.iterator();
		Class<?> wrapperClass = object;
		
		while(rs.next())
		{

			iter = st.iterator();
			Object obj = wrapperClass.getConstructor(boolean.class).newInstance(false);

			while(iter.hasNext())
			{
				String key = iter.next();
				
				Field field = wrapperClass.getDeclaredField(key);
				Method mt 	= null;
				try {
					Field clobField = wrapperClass.getDeclaredField(key+"CLOB");
					mt = wrapperClass.getMethod("set"+util.getFirstCaseUpper(key+"CLOB"),clobField.getType());
				}
				catch ( NoSuchFieldException nsfEx ) {
					mt 	= wrapperClass.getMethod("set"+util.getFirstCaseUpper(key),field.getType());
				}
				mt.invoke(obj, rs.getObject(key));
			}
			
			this.add(obj);
		}
		jimetDb.disconnect();
	}
	
	public void load(HashMap<String,String> fieldMapValueProp,String strSort, String strOrderBy ,Long startIndex, Long endIndex )  throws Exception 
	{
		if(fieldMapValueProp==null) fieldMapValueProp = new HashMap<String,String>();
		if(strSort==null) strSort = "ASC";
		if(strOrderBy==null) strOrderBy = "id";
		if(startIndex==null) startIndex = -1L;
		if(endIndex==null) endIndex = -1L;
		
		this.pos = -1;
		this.objectsVec = new Vector<Object>();
		
		HashMap<Object,Object> passMap = new HashMap<Object, Object>();
		
		for (Map.Entry<String, String> entry: fieldMapValueProp.entrySet()) 
		{
			String key = entry.getKey();
			String value = entry.getValue();
			
			if(key.indexOf('.')==-1)
			passMap.put(key, value);
			else
			{
				String[] strVals = key.split("\\.");
				passMap.put(this.object.getDeclaredField(strVals[0]).getType(), new String[]{strVals[0],strVals[1],value});
			}
		
		}
		
		JimetDB jimetDb = (JimetDB) db.newInstance();
		ResultSet rs = jimetDb.getResultSetByFieldsWithExpr(passMap,strSort, strOrderBy, startIndex, endIndex);
		TemplateUtil util = new TemplateUtil();

		LinkedHashMap<String, String> dbFieldProp = jimetDb.getDbFieldProp();
		
		Set<String> st = dbFieldProp.keySet();
		Iterator<String> iter = st.iterator();
		Class<?> wrapperClass = object;
		
		while(rs.next())
		{

			iter = st.iterator();
			Object obj = wrapperClass.getConstructor(boolean.class).newInstance(false);

			while(iter.hasNext())
			{
				String key = iter.next();
				
				Field field = wrapperClass.getDeclaredField(key);
				Method mt 	= null;
				try {
					Field clobField = wrapperClass.getDeclaredField(key+"CLOB");
					mt = wrapperClass.getMethod("set"+util.getFirstCaseUpper(key+"CLOB"),clobField.getType());
				}
				catch ( NoSuchFieldException nsfEx ) {
					mt 	= wrapperClass.getMethod("set"+util.getFirstCaseUpper(key),field.getType());
				}
				mt.invoke(obj, rs.getObject(key));
			}
			
			this.add(obj);
		}
		jimetDb.disconnect();
	}
	
	public void load(HashMap<String,String> fieldMapValueProp,Vector<String> sortVect , Vector<String> orderByVect ,Long startIndex, Long endIndex )  throws Exception 
	{
		if(fieldMapValueProp==null) fieldMapValueProp = new HashMap<String,String>();
		if(sortVect==null){ sortVect = new Vector<String>(); sortVect.add("ASC");}
		if(orderByVect==null){ orderByVect = new Vector<String>(); orderByVect.add("id");}
		if(startIndex==null) startIndex = -1L;
		if(endIndex==null) endIndex = -1L;
		
		this.pos = -1;
		this.objectsVec = new Vector<Object>();
		
		HashMap<Object,Object> passMap = new HashMap<Object, Object>();
		
		for (Map.Entry<String, String> entry: fieldMapValueProp.entrySet()) 
		{
			String key = entry.getKey();
			String value = entry.getValue();
			
			if(key.indexOf('.')==-1)
			passMap.put(key, value);
			else
			{
				String[] strVals = key.split("\\.");
				passMap.put(this.object.getDeclaredField(strVals[0]).getType(), new String[]{strVals[0],strVals[1],value});
			}
		
		}
		
		JimetDB jimetDb = (JimetDB) db.newInstance();
		ResultSet rs = jimetDb.getResultSetByFieldsWithExpr(passMap,sortVect, orderByVect, startIndex, endIndex);
		TemplateUtil util = new TemplateUtil();

		LinkedHashMap<String, String> dbFieldProp = jimetDb.getDbFieldProp();
		
		Set<String> st = dbFieldProp.keySet();
		Iterator<String> iter = st.iterator();
		Class<?> wrapperClass = object;
		
		while(rs.next())
		{

			iter = st.iterator();
			Object obj = wrapperClass.getConstructor(boolean.class).newInstance(false);

			while(iter.hasNext())
			{
				String key = iter.next();
				
				Field field = wrapperClass.getDeclaredField(key);
				
				Method mt 	= null;
				try {
					Field clobField = wrapperClass.getDeclaredField(key+"CLOB");
					mt = wrapperClass.getMethod("set"+util.getFirstCaseUpper(key+"CLOB"),clobField.getType());
				}
				catch ( NoSuchFieldException nsfEx ) {
					mt 	= wrapperClass.getMethod("set"+util.getFirstCaseUpper(key),field.getType());
				}
				mt.invoke(obj, rs.getObject(key));

			}
			
			this.add(obj);
		}
		jimetDb.disconnect();
	}

	public long getCount(HashMap<String,String> fieldMapValueProp)  throws Exception 
	{
		if(fieldMapValueProp==null) fieldMapValueProp = new HashMap<String,String>();
		
		HashMap<Object,Object> passMap = new HashMap<Object, Object>();
		
		for (Map.Entry<String, String> entry: fieldMapValueProp.entrySet()) 
		{
			String key = entry.getKey();
			String value = entry.getValue();
			
			if(key.indexOf('.')==-1)
			passMap.put(key, value);
			else
			{
				String[] strVals = key.split("\\.");
				passMap.put(this.object.getDeclaredField(strVals[0]).getType(), new String[]{strVals[0],strVals[1],value});
			}
		
		}
		
		long count = 0;
		JimetDB jimetDb = (JimetDB) db.newInstance();
		ResultSet rs = jimetDb.getCount( passMap );
		
		if( rs.next() )
			count = rs.getLong(1);

		jimetDb.disconnect();
		return count;
	}

	public void loadByIds(String[] strArrIds,String strSort, String strOrderBy )  throws Exception 
	{
		this.loadByIds(strArrIds,strSort,strOrderBy,-1,-1);			
	}
	
	public void loadByIds(String[] strArrIds,String strSort, String strOrderBy ,Integer startIndex, Integer endIndex )  throws Exception 
	{
		if(strArrIds==null) strArrIds = new String[]{"-1"};
		if(strSort==null) strSort = "ASC";
		if(strOrderBy==null) strOrderBy = "id";
		if(startIndex==null) startIndex = -1;
		if(endIndex==null) endIndex = -1;
		
		this.pos = -1;
		this.objectsVec = new Vector<Object>();
	
		JimetDB jimetDb = (JimetDB) db.newInstance();
		ResultSet rs = jimetDb.loadByIds(strArrIds,strSort, strOrderBy, startIndex, endIndex);
		TemplateUtil util = new TemplateUtil();

		LinkedHashMap<String, String> dbFieldProp = jimetDb.getDbFieldProp();
		
		Set<String> st = dbFieldProp.keySet();
		Iterator<String> iter = st.iterator();
		Class<?> wrapperClass = object;
		
		while(rs.next())
		{

			iter = st.iterator();
			Object obj = wrapperClass.getConstructor(boolean.class).newInstance(false);

			while(iter.hasNext())
			{
				String key = iter.next();
				Field field = wrapperClass.getDeclaredField(key);
				
				Method mt 	= null;
				try {
					Field clobField = wrapperClass.getDeclaredField(key+"CLOB");
					mt = wrapperClass.getMethod("set"+util.getFirstCaseUpper(key+"CLOB"),clobField.getType());
				}
				catch ( NoSuchFieldException nsfEx ) {
					mt 	= wrapperClass.getMethod("set"+util.getFirstCaseUpper(key),field.getType());
				}
				mt.invoke(obj, rs.getObject(key));

			}
			
			this.add(obj);
		}
		jimetDb.disconnect();
	}
	
	public String getDistinctIdsList ()  throws Exception
	{
		String returnStr	= "";
		Hashtable<String, String> distinctIdsHash	= new Hashtable<String, String>();
		
		Class<?> jimetObjectClass = object;		
		Method mt = jimetObjectClass.getMethod("getId");	
		
		if(!(this.isNull()) && this.objectsVec.size() > 0 )
		{
			for(int i=0;i<this.objectsVec.size();i++)
			{
				Object anObject = this.objectsVec.elementAt(i);
				distinctIdsHash.put(String.valueOf(mt.invoke(anObject)), "");

			}
			this.pos = -1;
			
			Enumeration<String> keys	= distinctIdsHash.keys();
			while ( keys.hasMoreElements() )
				returnStr	+= keys.nextElement() + " , ";
			
			if ( returnStr.length() > 3 )
				returnStr	= returnStr.substring(0,returnStr.length()-3);
		}
		else 
			returnStr	= "-1";
		
		return returnStr;
	}
	
	public void add(Object anObject)
	{
		if(this.isNull())
		{
			this.pos = -1;
			this.objectsVec = new Vector<Object>();
		}
		this.objectsVec.add(anObject);
	}

	public boolean contains(Object lookFor) throws Exception
	{
		Class<?> jimetObjectClass = object;		
		Method mt = jimetObjectClass.getMethod("getId");
		mt.invoke(lookFor);
		
		
		if(!(this.isNull()))
		{
			for(int i=0;i<this.objectsVec.size();i++)
			{
				Object anObject = this.objectsVec.elementAt(i);
				long anObjectId	= (Long)mt.invoke(anObject);
				long lookForId	= (Long)mt.invoke(lookFor);
				if( anObjectId == lookForId )
					return true;
			}
		}
		return false;
	}
	
	public void reset()
	{
		this.pos = -1;
	}

	public boolean isNull()
	{
		if(this.objectsVec == null)
			return true;
		else
			return false;
	}
	
	public boolean next()
	{
		if(!(this.isNull())) 
		{
			pos++;
			return  (pos < this.objectsVec.size());
		} 
		else
		{
			return false;
		}
	}

	public Object getNext()
	{
		return (Object) this.objectsVec.elementAt(this.pos);
	}
	
	public void setDb(Class<?> db) {
		this.db = db;
	}

	public Class<?> getDb() {
		return db;
	}

	public Class<?> getObject() {
		return object;
	}

	public void setObject(Class<?> object) {
		this.object = object;
	}
}
